/***********************************************************************

	This file is part of KEEL-software, the Data Mining tool for regression, 
	classification, clustering, pattern mining and so on.

	Copyright (C) 2004-2010
	
	F. Herrera (herrera@decsai.ugr.es)
    L. Sánchez (luciano@uniovi.es)
    J. Alcalá-Fdez (jalcala@decsai.ugr.es)
    S. García (sglopez@ujaen.es)
    A. Fernández (alberto.fernandez@ujaen.es)
    J. Luengo (julianlm@decsai.ugr.es)

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see http://www.gnu.org/licenses/
  
**********************************************************************/

package keel.Algorithms.Neural_Networks.NNEP_Clas.algorithm.classification;


import java.util.List;

import keel.Algorithms.Neural_Networks.NNEP_Clas.problem.classification.IClassifier;
import keel.Algorithms.Neural_Networks.NNEP_Clas.problem.classification.softmax.ClassificationProblemEvaluator;
import keel.Algorithms.Neural_Networks.NNEP_Clas.problem.errorfunctions.ClassificationAccuracyErrorFunction;
import keel.Algorithms.Neural_Networks.NNEP_Common.algorithm.NeuralNetAlgorithm;
import net.sf.jclec.IEvaluator;
import net.sf.jclec.base.AbstractIndividual;

/**
 * <p> Base implementation for all classification neural net algorithms.
 * @author Written by Pedro Antonio Gutierrez Penia (University of Cordoba) 16/7/2007
 * @version 0.1
 * @param <I> Object Type which should extend from AbstractIndividual
 * @since JDK1.5
 */

public class CCRElitistNeuralNetAlgorithm<I extends AbstractIndividual<IClassifier>> extends NeuralNetAlgorithm<I>
{
	/**
	 * <p>
	 * Base implementation for all classification neural net algorithms
	 * </p>
	 */
	/////////////////////////////////////////////////////////////////
	// --------------------------------------- Serialization constant
	/////////////////////////////////////////////////////////////////

	/** Generated by Eclipse */
	private static final long serialVersionUID = 7315342480632585002L;
	
	/////////////////////////////////////////////////////////////////
	// ------------------------------------------------- System state
	/////////////////////////////////////////////////////////////////
	
	/** Best individual of last generation */
	
	protected I bestCCRIndividual;

	/** Classification Accuracy Error function */
	
	private ClassificationAccuracyErrorFunction caErrorFunction = new ClassificationAccuracyErrorFunction();
	
	/////////////////////////////////////////////////////////////////
	// ------------------------------------------------- Constructors
	/////////////////////////////////////////////////////////////////

	/**
	 * <p>
	 * Empty constructor
	 * </p>
	 */
	
	public CCRElitistNeuralNetAlgorithm() 
	{
		super();
	}
	
	/////////////////////////////////////////////////////////////////
	// ------------------------------ Getting system state properties
	/////////////////////////////////////////////////////////////////
	
	/**
	 * <p>
	 * Returns the best individual of the population
	 * 
	 * @return I Best individual of the population
	 * </p>  
	 */
	
	public I getBestCCRIndividual() {
		return bestCCRIndividual;
	}
	
	/////////////////////////////////////////////////////////////////
	// ---------------------------- Implementing IAlgorithm interface
	/////////////////////////////////////////////////////////////////
	
	/**
	 * <p>
	 * Create individuals in population, evaluating before start rest
	 * of evolution
	 * </p>
	 */
	
	@SuppressWarnings("unchecked")
	public void doInit()
	{
		super.doInit();
		
		// Best CCR individual of the set
		bestCCRIndividual = (I) obtainBestClassifier(this.bset.subList(0, nofselSecondMutator), this.evaluator).copy();
	}

	/**
	 * <p>
	 * Implementation for the Update task
	 * </p>
	 */
	
	@SuppressWarnings("unchecked")
	protected void doUpdate()
	{
		super.doUpdate();
		// Include previous best CCR individual
		bset.add(1, bestCCRIndividual);
		
		// Remove last individual
		bset.remove(populationSize-1);
		
		// Best CCR individual of the set
		bestCCRIndividual = (I) obtainBestClassifier(this.bset.subList(0, nofselSecondMutator), this.evaluator).copy();
	}

	/////////////////////////////////////////////////////////////////
	// -------------------------------------------- Protected methods
	/////////////////////////////////////////////////////////////////
	
	/**
	 * <p>
	 * Returns best individual of a list of individuals using the MSEErrorFunction
	 *
	 * @param individuals list of individuals to obtain best
	 * @param evaluator NeuralNetEvaluator to use in individual evaluation
	 * 
	 * @return I Best classifier of the ensemble
	 * </p>
	 */
	
	@SuppressWarnings("unchecked")
	protected I obtainBestClassifier(List<I> individuals, IEvaluator evaluator){
		
		if(evaluator instanceof ClassificationProblemEvaluator){
			ClassificationProblemEvaluator clEvaluator = (ClassificationProblemEvaluator) evaluator;
	
			// Obtain best training classifier of the list
			I best = null;
			double bestCCR = 0;		
			for(int i=0; i<individuals.size(); i++){
				I individual = individuals.get(i);
				
				IClassifier classifier = (IClassifier) ((AbstractIndividual)individual).getGenotype();
				double CCR = clEvaluator.getTrainClassificationError(classifier, caErrorFunction);
				
				if(i==0 || CCR >= bestCCR){
					best = individual;
					bestCCR = CCR;
				}
			}
			return best;
		}
		return null;
	}
}

